package com.vanEngine.util
{
	import flash.display.Sprite;
	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	/**
	 * Van Engine HashMap
	 * <br><br>
	 * <ul>
	 *  <li>String类型数字与Number类型数值相同,会被视为相同的Key.如 hashMap[2] == hashMap["2"]<br><br></li> 
	 * 
	 * 	<li>支持通过方括号( [] )对 Key为String类型或Number类型的HashMap进行赋值与取值. <br>若Key为其他类型, 请用put函数进行赋值,并用get函数进行取值<br><br></li>
	 * 
	 * 	<li>若列表中仅包含String或Number类型的值作为Key, 可通过for,for each 关键字分别对HashMap的Key与Value进行遍历.若包含其他类型的Key,则需要通过eachKey, eachValue或 keys,values函数对HashMap进行遍历.<br><br></li>
	 * </ul>
	 * 
	 * 
	 * 
	 * <br><br><b>注意:</b>遍历或迭代HashMap过程中,尽量避免增删元素, 这样有可能会导致迭代失败,或产生不确定的bug.
	 * 
	 * 
	 * @author ZhongZw
	 * 
	 */	
	public dynamic class VHashMap extends Proxy implements IVMap
	{
		private var _content:Dictionary;
		
		private var _length:int;
		
		private var _keyCache:Array;
		
		private var _valueCache:Array;
		
		
		public function VHashMap()
		{
			super();
			
			_content= new Dictionary();
			
			_length = 0;
		}
		
		
		override flash_proxy function deleteProperty(name:*):Boolean
		{
			return remove( name );
		}
		
		override flash_proxy function getProperty(name:*):*
		{
			return get( name );
		}
		
		override flash_proxy function setProperty(name:*, value:*):void
		{	
			put( name, value );
		}
		
		override flash_proxy function nextName(index:int):String
		{
			return  keys()[index - 1];
		}
		
		override flash_proxy function nextNameIndex(index:int):int
		{
			index++;
			
			if( index > keys().length )
			{
				return 0;
			}
			
			return index;
		}
		
		override flash_proxy function nextValue(index:int):*
		{
			return values()[index - 1];
		}
		
		public function values():Array
		{
			if( !_valueCache )
			{
				_valueCache = [];
				
				for each( var val:* in _content )
				{
					_valueCache.push( val );
				}
			}
			
			return _valueCache;
		}
		
		public function keys():Array
		{
			if( !_keyCache )
			{
				_keyCache = [];
				
				for( var key:* in _content )
				{
					_keyCache.push( key );
				}
			}
			
			return _keyCache;
		}
		
		public function isEmpty():Boolean
		{
			return _length == 0;
		}
		
		public function clear():void
		{
			_length = 0;
			cleanCache();
			_content = new Dictionary();
		}
		
		public function length():int
		{
			return _length;
		}
		
		public function containsKey( k:* ):Boolean
		{
			return _content[k] != undefined;
		}
		
		public function containsValue( v:* ):Boolean
		{
			var t_values:Array = values();
			
			for( var i:int = 0; i < t_values.length; i++ )
			{
				if( t_values[i] === v ) return true;
			}
			
			return false;
		}
		
		public function put( k:*, v:* ):void
		{
			if( _content[k] == undefined ) 
			{
				_length++; 
			}
			
			_content[k] = v;
			
			cleanCache();
		}
		
		public function get( k:* ):*
		{
			return _content[k];
		}
		
		public function remove( k:* ):Boolean
		{
			if( delete _content[k] )
			{
				_length--;
				
				cleanCache();
				
				return true;
			}
			
			return false;
		}
		
		public function putAll( map:IVMap ):void
		{
			var t_keys:Array = map.keys();
			
			for( var i:int = 0; i < t_keys.length; i++ )
			{
				put( t_keys[i], map.get( t_keys[i] ) );
			}
		}
		
		public function eachValue( func:Function ):void
		{
			var t_values:Array = values();
			
			for( var i:int = 0; i < t_values.length; i++ )
			{
				func( t_values[i] );
			}
		}
		
		public function eachKey( func:Function ):void
		{
			var t_keys:Array = keys();
			
			for( var i:int = 0; i < t_keys.length; i++ )
			{
				func( t_keys[i] );
			}
		}
		
		private function cleanCache():void
		{
			this._keyCache = null;
			
			this._valueCache = null;
		}
		
		public function toString():String
		{
			var t_str:String = "{";
			
			var t_keys:Array = keys();
			
			for( var i:int = 0; i < t_keys.length; i++ )
			{
				if( i > 0 ) t_str += ",";
				
				if(  t_keys[i] is String )
				{
					t_str += "\"" + t_keys[i] + "\"" + ":" + _content[t_keys[i]];
				}
				else
				{
					t_str += t_keys[i] + ":" + _content[t_keys[i]];
				}
				
			}
			
			t_str += "}";
			
			return t_str;
		}
		
	}
}